package com.lifesting.tool.j2as3.visitor;

import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

public class ClassHierarchy {
	private final ClassNode CLASS_ROOT = new ClassNode(".CLASS.ROOT");
	private final InterfaceNode INTERFACE_ROOT = new InterfaceNode(".INTERFACE.ROOT");
	private final Node ROOT;
	public ClassHierarchy()
	{
		ROOT = new Node(".ROOT"){
			{
				children.add(CLASS_ROOT);
				children.add(INTERFACE_ROOT);
				CLASS_ROOT.parent = this;
				INTERFACE_ROOT.parent = this;
			}
		};
	}
	public ClassNode insertClass(ClassNode cn){
		return (ClassNode) insertNode(cn, CLASS_ROOT);
	}
	public InterfaceNode insertInterface(InterfaceNode in){
		return (InterfaceNode) insertNode(in, INTERFACE_ROOT);
	}
	public Node insertNode(Node node, Node tree){
		final Node local_node = node;
		final Node[] match = new Node[1];
		tree.accept(new Visitor(){
			public void endVisit(Node n) {
			}
			public boolean visit(Node n) {
				if (n.getQualifiedName().equals(local_node.getQualifiedName())){
					match[0] = n;
					return false;
				}
				return true;
			}});
		List<Node> children = local_node.getChildren();
		final List<Node> level_0_children = tree.getChildren();
		final Map<Node, Node> parent_mark = new HashMap<Node, Node>();
		Visitor mark_visitor = new Visitor() {
		
			public boolean visit(com.lifesting.tool.j2as3.visitor.Node n) {
				for (Node L0_node : level_0_children){
					if (L0_node.getQualifiedName().equals(n.getQualifiedName())){
						parent_mark.put(n.getParent(), L0_node);
					}
				}
				return true;
			}
		
			public void endVisit(com.lifesting.tool.j2as3.visitor.Node n) {
		
			}
		};
		
		for (Node cn : children){
			cn.accept(mark_visitor);
		}
		for (Iterator<Node> parent_iter = parent_mark.keySet().iterator(); parent_iter.hasNext();){
			Node parent_node = parent_iter.next();
			Node child_node = parent_mark.get(parent_node);
			tree.removeChild(child_node);
			parent_node.addChild(child_node);
		}
		if (match[0] == null){
			tree.addChild(local_node);
			return local_node;
		}else{
			match[0].addGroup(children);
			return match[0];
		}
	}
	public Node getRoot(){
		return ROOT;
	}
	public void accept(Visitor visitor)
	{
		for (Node n: CLASS_ROOT.children){
			n.accept(visitor);
		}
		for (Node n : INTERFACE_ROOT.children){
			n.accept(visitor);
		}
	}
}
